<template>
	<view
		class="e-search"
		@tap="clickHandler"
		:style="[
			{
				margin: props.margin
			},
			addStyle(props.customStyle)
		]"
	>
		<view class="e-search__content" :style="[contentStyle]">
			<template v-if="labelShow">
				<slot name="label">
					<text class="e-search__content__label">{{ props.label }}</text>
				</slot>
			</template>
			<view class="e-search__content__icon">
				<e-icon @click="clickIcon" :size="props.searchIconSize" :name="props.searchIcon" :color="props.searchIconColor ? props.searchIconColor : props.color"></e-icon>
			</view>
			<view class="e-search__content__input-box">
				
				<e-transition :show="!!props.modelValue && props.showValueLabel && !focused">
					<view class="e-search__content__input-label" :style="[{ height: addUnit(props.height) }]">
						<view class="e-search__content__input-label__text">
							<text>{{ props.modelValue }}</text>
						</view>
						<e-icon @click="onClear" size="6" name="close" color="#fff"></e-icon>
					</view>
				</e-transition>
				<input
					class="e-search__content__input"
					confirm-type="search"
					v-model="keyword"
					@confirm="search"
					:disabled="props.disabled"
					@blur="blur"
					@focus="getFocus"
					:focus="props.focus"
					:maxlength="props.maxlength"
					:placeholder-class="props.placeholderClass"
					:placeholder="props.placeholder"
					:placeholder-style="`color: ${props.placeholderColor}`"
					type="text"
					:style="[inputStyle, props.inputStyle]"
				/>
			</view>

			<view class="e-search__content__icon e-search__content__close" v-if="keyword && props.clearabled && focused" @tap="onClear">
				<e-icon name="close" size="11" color="#ffffff" customStyle="line-height: 12px"></e-icon>
			</view>
			<view class="e-search__content__button" v-if="props.actionText && props.showActionButton" @tap.stop.prevent="custom">
				<e-button type="primary" :text="props.actionText" shape="circle"></e-button>
			</view>
		</view>
		<text :style="[props.actionStyle]" class="e-search__action" :class="[showActionBtn && 'e-search__action--active']" @tap.stop.prevent="custom">{{ props.actionText }}</text>
	</view>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import mpMixin from '../../libs/mixin/mpMixin';
/**
 * search 搜索框
 * @description 搜索组件，集成了常见搜索框所需功能，用户可以一键引入，开箱即用。
 * @tutorial https://www.uviewui.com/components/search.html
 * @property {String}			shape				搜索框形状，round-圆形，square-方形（默认 'round' ）
 * @property {String}			bgColor				搜索框背景颜色（默认 '#f2f2f2' ）
 * @property {String}			placeholder			占位文字内容（默认 '请输入关键字' ）
 * @property {Boolean}			clearabled			是否启用清除控件（默认 true ）
 * @property {Boolean}			focus				是否自动获得焦点（默认 false ）
 * @property {Boolean}			showAction			是否显示右侧控件（默认 true ）
 * @property {Object}			actionStyle			右侧控件的样式，对象形式
 * @property {String}			actionText			右侧控件文字（默认 '搜索' ）
 * @property {String}			showActionButton	右侧控件替换为按钮控件（优先级高于showAction）
 * @property {String}			inputAlign			输入框内容水平对齐方式 （默认 'left' ）
 * @property {Object}			inputStyle			自定义输入框样式，对象形式
 * @property {Boolean}			disabled			是否启用输入框（默认 false ）
 * @property {String}			borderColor			边框颜色，配置了颜色，才会有边框 (默认 'transparent' )
 * @property {String}			color				输入框字体颜色（默认 '#606266' ）
 * @property {String}			placeholderClass	指定placeholder的样式类，注意页面或组件的style中写了scoped时，需要在类名前写.deep （ 默认 'input-placeholder' ）
 * @property {String}			placeholderColor	placeholder的颜色（默认 '#909399' ）
 * @property {String}			searchIcon			输入框左边的图标，可以为uView图标名称或图片路径  (默认 'search' )
 * @property {String}			searchIconColor		搜索图标的颜色，默认同输入框字体颜色 (默认 '#909399' )
 * @property {Number | String}	searchIconSize 		搜索图标的字体，默认22
 * @property {String}			margin				组件与其他上下左右元素之间的距离，带单位的字符串形式，如"30px"   (默认 '0' )
 * @property {Boolean} 			animation			是否开启动画，见上方说明（默认 false ）
 * @property {String}			value				输入框初始值
 * @property {String | Number}	maxlength			输入框最大能输入的长度，-1为不限制长度  (默认 '-1' )
 * @property {String | Number}	height				输入框高度，单位px（默认 64 ）
 * @property {String | Number}	label				搜索框左边显示内容
 * @property {Boolean}			showValueLabel		是否显示右侧控件（默认 false ）
 * @property {Object}			customStyle			定义需要用到的外部样式
 *
 * @event {Function} change 输入框内容发生变化时触发
 * @event {Function} search 用户确定搜索时触发，用户按回车键，或者手机键盘右下角的"搜索"键时触发
 * @event {Function} custom 用户点击右侧控件时触发
 * @event {Function} clear 用户点击清除按钮时触发
 * @example <e-search placeholder="日照香炉生紫烟" v-model="keyword"></e-search>
 */
export default defineComponent({
	name: 'e-search',
	mixins: [mpMixin]
});
</script>

<script lang="ts" setup>
import { ref, computed, nextTick, getCurrentInstance, toRefs } from 'vue';
import { useDefaultProps } from '../../libs/hooks';
import { searchProps, searchEmits } from './props';
import { addStyle, addUnit } from '../../libs/utils/_utils';
import { isString, isNumber } from '../../libs/utils';
import componentsProps, { type DefaultProps } from '../../libs/config/componentsProps';
import type { InputEvent } from '../../libs/config';

const { search: searchDefaultProps } = toRefs(componentsProps);

const _props = defineProps(searchProps);

const props = useDefaultProps<DefaultProps['search']>(_props, searchDefaultProps);
const emit = defineEmits(searchEmits);

const ctx = getCurrentInstance();

const show = ref(false);
const focused = ref(false);

const keyword = computed({
	get() {
		// 当showValueLabel设置为true时，在失焦的情况下，输入框内容显示为空
		return !!props.value.modelValue&&props.value.showValueLabel && !focused.value ? '  ' : props.value.modelValue;
	},
	set(v) {
		emit('input', v);
		emit('update:modelValue', v);
		// 触发change事件，事件效果和v-model双向绑定的效果一样，让用户多一个选择
		emit('change', v);
	}
});

const labelShow = computed(() => {
	return ctx?.slots?.label || isString(props.value.label) || isNumber(props.value.label);
});

const contentStyle = computed(() => {
	return {
		backgroundColor: props.value.bgColor,
		borderRadius: props.value.shape == 'round' ? '100px' : '4px',
		borderColor: props.value.borderColor
	};
});
const inputStyle = computed(() => {
	return {
		textAlign: props.value.inputAlign,
		color: props.value.color,
		backgroundColor: props.value.bgColor,
		height: addUnit(props.value.height),
		lineHeight: addUnit(props.value.height)
	};
});

const showActionBtn = computed(() => {
	return (!props.value.animation && props.value.showAction && !props.value.showActionButton) || show.value;
});

// // 内容发生变化，进行处理
// const valueChange = () => {
// 	const value = keyword.value;
// 	nextTick(() => {
// 		emit("input", value);
// 		emit("update:modelValue", value);
// 		emit("change", value);
// 	});
// }
// 点击清除控件
const onClear = () => {
	keyword.value = '';
	nextTick(() => {
		// valueChange();
		emit('clear');
	});
};

// 确定搜索
const search = (e: InputEvent) => {
	emit('search', e.detail.value);
	try {
		// 收起键盘
		uni.hideKeyboard();
	} catch (e) {}
};
// 点击右边自定义按钮的事件
const custom = () => {
	emit('custom', keyword.value);
	try {
		// 收起键盘
		uni.hideKeyboard();
	} catch (e) {}
};
// 获取焦点
const getFocus = () => {
	focused.value = true;
	// 开启右侧搜索按钮展开的动画效果
	if (props.value.animation && props.value.showAction) show.value = true;
	emit('focus', keyword.value);
};
// 失去焦点
const blur = () => {
	// 最开始使用的是监听图标@touchstart事件，自从hx2.8.4后，此方法在微信小程序出错
	// 这里改为监听点击事件，手点击清除图标时，同时也发生了@blur事件，导致图标消失而无法点击，这里做一个延时
	setTimeout(() => {
		focused.value = false;
	}, 100);
	show.value = false;
	emit('blur', keyword.value);
};
// 点击搜索框，只有disabled=true时才发出事件，因为禁止了输入，意味着是想跳转真正的搜索页
const clickHandler = () => {
	if (props.value.disabled) emit('click');
};
// 点击左边图标
const clickIcon = () => {
	emit('clickIcon');
};
</script>

<style lang="scss" scoped>
@import '../../libs/theme/search.scss';
</style>
